package minio

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"oa-rest/common"
	"path/filepath"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/minio/minio-go/v7"
)

// BucketInfo bucket信息
type BucketInfo struct {
	Name     string `json:"name"`
	FileCount int   `json:"fileCount"`
}

// DocumentInfo 文档信息
type DocumentInfo struct {
	Name         string  `json:"name"`
	Size         int64   `json:"size"`
	LastModified string  `json:"lastModified"`
	URL          string  `json:"url"`
	ContentType  string  `json:"contentType"`
}


// ListBucketsHandler 获取所有bucket列表
func ListBucketsHandler(c *gin.Context) {
	// 获取MinIO客户端
	minioClient := common.MinioClient
	if minioClient == nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code":    500,
			"message": "MinIO客户端未初始化",
			"data":    nil,
		})
		return
	}

	// 使用MinIO客户端列出所有bucket
	ctx := context.Background()
	bucketList, err := minioClient.Client.ListBuckets(ctx)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code":    500,
			"message": "获取bucket列表失败: " + err.Error(),
			"data":    nil,
		})
		return
	}

	// 构造返回数据
	var buckets []BucketInfo
	for _, bucket := range bucketList {
		// 获取bucket中的对象数量
		objectCh := minioClient.Client.ListObjects(ctx, bucket.Name, minio.ListObjectsOptions{
			Recursive: true,
		})

		fileCount := 0
		for object := range objectCh {
			if object.Err != nil {
				log.Printf("列出对象错误: %v", object.Err)
				break
			}
			fileCount++
		}

		buckets = append(buckets, BucketInfo{
			Name:      bucket.Name,
			FileCount: fileCount,
		})
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    200,
		"message": "获取bucket列表成功",
		"data":    buckets,
	})
}

// GetBucketDocumentsHandler 获取指定bucket的文档列表
func GetBucketDocumentsHandler(c *gin.Context) {
	bucketName := c.Param("bucketName")
	prefix := c.DefaultQuery("prefix", "")

	var objects []DocumentInfo
	var err error

	switch bucketName {
	case "test":
		objects, err = getDocumentsFromBucket(common.MinioClient, prefix)
	case "documents":
		objects, err = getDocumentsFromBucket(common.DocumentClient, prefix)
	case "meeting":
		objects, err = getDocumentsFromBucket(common.MeetingClient, prefix)
	default:
		// 对于动态bucket（如user-001, user_001等），使用通用MinIO客户端
		objects, err = getDocumentsFromDynamicBucket(bucketName, prefix)
	}

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code":    500,
			"message": "获取文档列表失败: " + err.Error(),
			"data":    nil,
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    200,
		"message": "获取文档列表成功",
		"data": gin.H{
			"bucket": bucketName,
			"prefix": prefix,
			"documents": objects,
		},
	})
}

// DownloadDocumentHandler 下载文档
func DownloadDocumentHandler(c *gin.Context) {
	bucketName := c.Param("bucketName")
	objectName := c.Param("objectName")

	var data []byte
	var err error

	switch bucketName {
	case "test":
		url := common.MinioClient.GeneratePermanentURL(objectName)
		data, err = common.MinioClient.DownloadFileBytes(url)
	case "documents":
		data, err = common.DownloadDocument(objectName)
	case "meeting":
		data, err = common.DownloadMeeting(objectName)
	default:
		// 对于动态bucket（如user-001, user_001等），使用通用MinIO客户端
		url := fmt.Sprintf("http://%s/%s/%s", common.MinioClient.Client.EndpointURL().Host, bucketName, objectName)
		data, err = common.MinioClient.DownloadFileBytes(url)
	}

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code":    500,
			"message": "下载文档失败: " + err.Error(),
			"data":    nil,
		})
		return
	}

	// 设置响应头
	c.Header("Content-Disposition", "attachment; filename="+filepath.Base(objectName))
	c.Header("Content-Type", "application/octet-stream")
	c.Data(http.StatusOK, "application/octet-stream", data)
}

// GetDocumentURLHandler 获取文档访问URL
func GetDocumentURLHandler(c *gin.Context) {
	bucketName := c.Param("bucketName")
	objectName := c.Param("objectName")

	var url string

	switch bucketName {
	case "test":
		url = common.MinioClient.GeneratePermanentURL(objectName)
	case "documents":
		url = common.GenerateDocumentURL(objectName)
	case "meeting":
		url = common.GenerateMeetingURL(objectName)
	default:
		// 对于动态bucket（如user-001, user_001等），生成通用URL
		url = fmt.Sprintf("http://%s/%s/%s", common.MinioClient.Client.EndpointURL().Host, bucketName, objectName)
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    200,
		"message": "获取文档URL成功",
		"data": gin.H{
			"url": url,
		},
	})
}

// DeleteDocumentHandler 删除文档
func DeleteDocumentHandler(c *gin.Context) {
	bucketName := c.Param("bucketName")
	objectName := c.Param("objectName")

	var err error

	switch bucketName {
	case "test":
		err = common.MinioClient.DeleteObject(objectName)
	case "documents":
		err = deleteFromBucket(common.DocumentClient, objectName)
	case "meeting":
		err = deleteFromBucket(common.MeetingClient, objectName)
	default:
		// 对于动态bucket（如user-001, user_001等），使用通用MinIO客户端删除
		err = common.MinioClient.Client.RemoveObject(context.Background(), bucketName, objectName, minio.RemoveObjectOptions{})
	}

	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code":    500,
			"message": "删除文档失败: " + err.Error(),
			"data":    nil,
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    200,
		"message": "删除文档成功",
		"data":    nil,
	})
}

// 辅助函数
func getCountFromBucket(client interface{}) int {
	if client == nil {
		return 0
	}

	// 使用反射或类型断言来调用ListObjects方法
	switch c := client.(type) {
	case interface{ ListObjects(string) ([]minio.ObjectInfo, error) }:
		objects, err := c.ListObjects("")
		if err != nil {
			return 0
		}
		return len(objects)
	default:
		return 0
	}
}

func getDocumentsFromBucket(client interface{}, prefix string) ([]DocumentInfo, error) {
	if client == nil {
		return nil, nil
	}

	var objects []minio.ObjectInfo
	var err error

	switch c := client.(type) {
	case interface{ ListObjects(string) ([]minio.ObjectInfo, error) }:
		objects, err = c.ListObjects(prefix)
	}

	if err != nil {
		return nil, err
	}

	var docs []DocumentInfo
	for _, obj := range objects {
		docs = append(docs, DocumentInfo{
			Name:         obj.Key,
			Size:         obj.Size,
			LastModified: obj.LastModified.Format("2006-01-02 15:04:05"),
			ContentType:  getContentTypeFromKey(obj.Key),
		})
	}

	return docs, nil
}

func deleteFromBucket(client interface{}, objectName string) error {
	if client == nil {
		return nil
	}

	switch c := client.(type) {
	case interface{ DeleteObject(string) error }:
		return c.DeleteObject(objectName)
	}

	return nil
}

func getContentTypeFromKey(key string) string {
	ext := strings.ToLower(filepath.Ext(key))
	switch ext {
	case ".pdf":
		return "application/pdf"
	case ".doc", ".docx":
		return "application/msword"
	case ".xls", ".xlsx":
		return "application/vnd.ms-excel"
	case ".ppt", ".pptx":
		return "application/vnd.ms-powerpoint"
	case ".txt":
		return "text/plain"
	case ".md":
		return "text/markdown"
	case ".jpg", ".jpeg":
		return "image/jpeg"
	case ".png":
		return "image/png"
	case ".gif":
		return "image/gif"
	case ".mp3":
		return "audio/mpeg"
	case ".wav":
		return "audio/wav"
	case ".mp4":
		return "video/mp4"
	case ".zip":
		return "application/zip"
	default:
		return "application/octet-stream"
	}
}

// getDocumentsFromDynamicBucket 从动态bucket获取文档列表
func getDocumentsFromDynamicBucket(bucketName, prefix string) ([]DocumentInfo, error) {
	if common.MinioClient == nil {
		return nil, fmt.Errorf("MinIO客户端未初始化")
	}

	// 检查bucket是否存在
	ctx := context.Background()
	exists, err := common.MinioClient.Client.BucketExists(ctx, bucketName)
	if err != nil {
		return nil, fmt.Errorf("检查bucket存在失败: %v", err)
	}

	if !exists {
		return nil, fmt.Errorf("bucket %s 不存在", bucketName)
	}

	// 列出bucket中的对象
	objectsCh := common.MinioClient.Client.ListObjects(ctx, bucketName, minio.ListObjectsOptions{
		Prefix:    prefix,
		Recursive: true,
	})

	var docs []DocumentInfo
	for object := range objectsCh {
		if object.Err != nil {
			return nil, fmt.Errorf("列出对象错误: %v", object.Err)
		}

		docs = append(docs, DocumentInfo{
			Name:         object.Key,
			Size:         object.Size,
			LastModified: object.LastModified.Format("2006-01-02 15:04:05"),
			ContentType:  getContentTypeFromKey(object.Key),
			URL:          fmt.Sprintf("http://%s/%s/%s", common.MinioClient.Client.EndpointURL().Host, bucketName, object.Key),
		})
	}

	return docs, nil
}